﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Xml.Linq;

namespace ApiDoc
{
    partial class ApiDocumentationManager
    {
        /// <summary>
        /// Add <paramref name="document"/> to the list of available XML documents.
        /// </summary>
        /// <param name="document"></param>
        public void AddXml(XDocument document)
        {
            m_documents.Add(document);
        }
        /// <summary>
        /// Add <paramref name="documents"/> to the list of available XML documents.
        /// </summary>
        /// <param name="documents"></param>
        public void AddXmlRange(params XDocument[] documents)
        {
            AddXmlRange(documents.ToList());
        }

        /// <summary>
        /// Add <paramref name="documents"/> to the list of available XML documents.
        /// </summary>
        /// <param name="documents"></param>
        public void AddXmlRange(IEnumerable<XDocument> documents)
        {
            foreach (var document in documents) {
                m_documents.Add(document);
            }
        }

        private List<XDocument> m_documents = new List<XDocument>();

        /// <summary>
        /// Returns the XML documentation for <paramref name="member"/> 
        /// </summary>
        /// <param name="member"></param>
        /// <returns></returns>
        public XElement GetXmlDocumentation(MemberInfo member)
        {
            var cref = CRef.ReflectionCRefGenerator.WithPrefix.GetCRef(member);

            XElement ret = null;
            foreach (var document in m_documents) {
                ret = document.Descendants("member")
                    .Where(item => (string)item.Attribute("name") == cref)
                    .FirstOrDefault();

                if (ret != null) {
                    break;
                }
            }

            // If the member hasn't got any documentation then try looking up through is parent types.
            if (ret == null) {
                if (member is Type) {
                    // See if we can get the documetnation from the base type.
                    var baseType = ((Type)member).BaseType;
                    if (baseType != null) {
                        ret = GetXmlDocumentation(baseType);
                    }
                } else if (member is MethodInfo) {
                    // See if we can get the documetnation from the base type.
                    var baseMethod = ((MethodInfo)member).GetBaseDefinition();
                    if (baseMethod != null && baseMethod != member) {
                        ret = GetXmlDocumentation(baseMethod);
                    }                    
                } else if (member is PropertyInfo) {
                    // See if we can get the documetnation from the base type.
                    var baseType = ((PropertyInfo)member).ReflectedType.BaseType;
                    if (baseType != null) {
                        var property = baseType.GetProperty(member.Name);
                        if (property != null && property != member) {
                            ret = GetXmlDocumentation(property);
                        }
                    }                    
                }
            }

            return ret;
        }

        /// <summary>
        /// Returns the XML documentation for <paramref name="member"/> 
        /// </summary>
        /// <param name="member"></param>
        /// <returns></returns>
        public XElement GetXmlDocumentation(ParameterInfo member)
        {
            var parentElement = GetXmlDocumentation(member.Member);
            if (parentElement == null) {
                return null;
            }

            var ret = parentElement.Descendants("param")
                .FirstOrDefault(item => (string)item.Attribute("name") == member.Name);

            return ret;
        }
    }
}
